<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/4/5
 * Time: 13:38
 */

namespace common\helps;


class Image
{
    /**
     * 水印位置
     */
    const WATER_CENTER = 1;
    const WATER_LEFT_UP = 2;
    const WATER_LEFT_DOWN = 3;
    const WATER_RIGHT_UP = 4;
    const WATER_RIGHT_DOWN = 5;

    protected $config = [
        'savePath'=>'',//保存路径
        'saveExt'=>'',//保存后缀无就是原图片类型
        'maxWidth'=>0,//最大宽度
        'maxHeight'=>0,//最大高度
        'width'=>0,//保存宽度无就是原图片
        'height'=>0,//保存高度无就是原图片
        'water'=>'',//水印文件
        'waterPosition'=>self::WATER_RIGHT_DOWN,//水印位置
        'fillColor'=>'225, 255, 255',//填充颜色
        'fontFile'=>'',//字体文件
        'fontColor'=>'225, 255, 255',//字体颜色
    ];

    private $imageExt = '';
    private $imagePath = '';
    private $imageName = '';
    private $imageWidth = 0;
    private $imageHeight = 0;

    protected $errorInfo = '';
    private $tmpInfo = [];

    public function __construct($config)
    {
        foreach($config as $key => $value)
        {
            $this->setConfig($key, $value);
        }
    }

    /**
     * 设置配置
     * @param $key
     * @param $value
     * @return bool
     */
    public function setConfig($key, $value)
    {
        if(isset($this->config[$key]))
        {
            $this->config[$key] = $value;
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     *图片自动处理
     * @param array|string $source
     * @return bool
     */
    public function autoImage($source)
    {
        if(!file_exists($source))
        {
            $this->error('文件不存在');
            return false;
        }

        $this->imageExt = pathinfo($source, PATHINFO_EXTENSION);
        $this->imageName = pathinfo($source, PATHINFO_FILENAME);
        $this->imagePath = realpath($source);
        list($width, $height, $type, $attr) = getimagesize($source);
        $this->imageHeight = $height;
        $this->imageWidth = $width;
        $this->imageExt = image_type_to_extension ($type, false);

        $imageSource = $this->equalScaling($source, $this->config['maxWidth'], $this->config['maxHeight']);
        $imageSource = $this->water(null, $this->config['water'], $this->config['waterPosition'], $this->config['fontColor']);
        return $imageSource;
    }

    /**
     * 保存错误信息
     * @param $msg
     */
    protected function error($msg)
    {
        $this->errorInfo = $msg;
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->errorInfo;
    }

    /**
     * 等比例缩放
     * @param $source
     * @param int $maxWidth
     * @param int $maxHeight
     * @return mixed
     */
    public function equalScaling($source, $maxWidth = 0, $maxHeight = 0)
    {
        $imageInfo = getimagesize($source);
        $sourceImage = $this->getSourceImage($source);
        $this->setTmp([
            'width' => $imageInfo[0],
            'height' => $imageInfo[1],
            'source' => $sourceImage,
        ]);
        $newWidth = $imageInfo[0];
        $newHeight = $imageInfo[1];
        if(($maxHeight > 0 && $maxHeight < $imageInfo[1]) || ($maxWidth > 0 && $maxWidth < $imageInfo[0]))
        {
            $widthRate = $maxWidth && $maxWidth < $imageInfo[0] ? $maxWidth / $imageInfo[0] : 1;
            $heightRate = $maxHeight && $maxHeight < $imageInfo[1] ? $maxHeight / $imageInfo[1] : 1;
            $rate = $widthRate > $heightRate ? $heightRate : $widthRate;
            $newWidth = floor($newWidth * $rate);
            $newHeight = floor($newHeight * $rate);
            $newImage = imagecreatetruecolor($newWidth, $newHeight);
            imagefill($newImage, 0, 0, imagecolorallocatealpha($newImage, 255, 255, 255, 127));
            imagecopyresized($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $imageInfo[0], $imageInfo[1]);

            imagedestroy($sourceImage);
            $this->setTmp([
                'width' => $newWidth,
                'height' => $newHeight,
                'source' => $newImage,
            ]);
            return $newImage;
        }

        return $sourceImage;
    }

    /**
     * 限制宽高填充
     * @param string $source
     * @param int $width
     * @param int $height
     * @param string $color
     * @return resource
     */
    public function fillImage($source, $width, $height, $color = '')
    {
        $eqImage = $this->equalScaling($source, $width, $height);
        $newImage = imagecreatetruecolor($width, $height);
        list($red, $green, $blue) = $this->getColor($color);

        $col = imagecolorallocate($newImage, $red, $green, $blue);
        imagefill($newImage, 0, 0, $col);

        $eqWidth = $this->tmpInfo['width'];
        $eqHeight = $this->tmpInfo['height'];
        $newX = $width > $eqWidth ? floor(($width - $eqWidth) / 2) : 0;
        $newY = $height > $eqHeight ? floor(($height - $eqHeight) / 2) : 0;
        imagecopy($newImage, $eqImage, $newX, $newY, 0, 0, $eqWidth, $eqHeight);
        imagedestroy($eqImage);
        $this->setTmp([
            'width'=>$width,
            'height'=>$height,
            'source'=>$newImage,
        ]);
        return $newImage;
    }

    /**
     * 获取颜色 格式 255,255,255 红绿蓝
     * @param string $color
     * @return array
     */
    public function getColor($color)
    {
        if($color)
        {
            $color = array_filter(array_map(function($val){
                $val = trim($val);
                return is_numeric($val) && $val >=0 && $val < 256 ? intval($val) : null;
            }, explode(',', $color)), 'is_numeric');
            if(count($color) == 3)
            {
                return $color;
            }
        }

        return [255, 255, 255];
    }

    /**
     * 加水印
     * @param string $source
     * @param string $water
     * @param null $position
     * @param string $color
     * @return mixed
     */
    public function water($source = '', $water = '', $position = null, $color = '')
    {
        /*如果源路径为空就使用缓存资源*/
        $image = $source ? $this->getSourceImage($source) : $this->tmpInfo['source'];
        $imageWidth = $this->tmpInfo['width'];
        $imageHeight = $this->tmpInfo['height'];
        /*图片水印*/
        if(file_exists($water) && $waterImage = $this->equalScaling($water, $imageWidth / 2, $imageHeight / 2))
        {
            $waterWidth = $this->tmpInfo['width'];
            $waterHeight = $this->tmpInfo['height'];
            $x = 0;
            $y = 0;
            switch($position)
            {
                case self::WATER_CENTER:
                    $x = floor(($imageWidth - $waterWidth) / 2);
                    $y = floor(($imageHeight - $waterHeight) / 2);
                    break;
                case self::WATER_LEFT_UP:
                    $x = 0;
                    $y = 0;
                    break;
                case self::WATER_LEFT_DOWN:
                    $x = 0;
                    $y = $imageHeight - $waterHeight;
                    break;
                case self::WATER_RIGHT_UP:
                    $x = $imageWidth - $waterWidth;
                    $y = 0;
                    break;
                case self::WATER_RIGHT_DOWN:
                    $x = $imageWidth - $waterWidth;
                    $y = $imageHeight - $waterHeight;
                    break;
            }
            imagecopy($image, $waterImage, $x, $y, 0, 0, $waterWidth, $waterHeight);
            imagedestroy($waterImage);
        }
        else /*文字水印*/
        {
            list($red, $green, $blue) = $this->getColor($color);
            $color = imagecolorallocate($image, $red, $green, $blue);
            list($waterWidth, $waterHeight) = $this->getFontSize($water);
            $padding = 10;
            switch($position)
            {
                case self::WATER_CENTER:
                    $x = floor(($imageWidth - $waterWidth) / 2);
                    $y = floor(($imageHeight - $waterHeight) / 2);
                    break;
                case self::WATER_LEFT_UP:
                    $x = $padding;
                    $y = $padding;
                    break;
                case self::WATER_LEFT_DOWN:
                    $x = $padding;
                    $y = $imageHeight - $waterHeight - $padding;
                    break;
                case self::WATER_RIGHT_UP:
                    $x = $imageWidth - $waterWidth - $padding;
                    $y = $padding;
                    break;
                case self::WATER_RIGHT_DOWN:
                default:
                    $x = $imageWidth - $waterWidth - $padding;
                    $y = $imageHeight - $waterHeight - $padding;;
                    break;
            }

            imagettftext($image, 12, 0, $x, $y, $color, $this->config['fontFile'], $water);
        }
        return $image;
    }

    /**
     * 获取文字宽高度
     * @param $string
     * @return array
     */
    public function getFontSize($string)
    {
        $ttf = imagettfbbox(12, 0, $this->config['fontFile'], $string);
        $x = [
            $ttf[0],
            $ttf[2],
            $ttf[4],
            $ttf[6],
        ];
        $y = [
            $ttf[1],
            $ttf[3],
            $ttf[5],
            $ttf[7],
        ];
        $width = max($x) - min($x);
        $height = max($y) - min($y);
        return [$width, $height];
    }

    public function save($image, $path = '')
    {
        if(!$path)
        {
            $path = $this->config['savePath'];
        }
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        switch($ext)
        {
            case 'jpg':
                $ext = 'jpeg';
            case 'jpeg':
            case 'png':
            case 'gif':
            case 'wbmp':
                $func = 'image'.$ext;
                return $func($image, $path);
                break;
            default:
        }
        return false;
    }

    /**
     * 设置缓存信息
     * @param $info
     */
    public function setTmp($info)
    {
        /*isset($this->tmpInfo['source']) && imagedestroy($this->tmpInfo['source']);*/
        $this->tmpInfo = $info;
    }

    /**
     * 展示图
     * @param $gdObj
     */
    public function show($gdObj)
    {
        ob_clean();
        header("Content-type: image/jpeg");
        imagejpeg($gdObj);
        exit();
    }

    /**
     * 获取图像资源
     * @param $source
     * @return mixed
     */
    public function getSourceImage($source)
    {
        $imageInfo = getimagesize($source);
        $func = $this->getImageFunction('imagecreatefrom', $source);
        $image = $func($source);
        $this->setTmp([
            'width'=>$imageInfo[0],
            'height'=>$imageInfo[1],
            'source'=>$image,
        ]);
        return $image;
    }

    /**
     * 获取GD2图像函数名
     * @param $func
     * @param $source
     * @return bool|string
     */
    public function getImageFunction($func, $source)
    {
        $type = $this->getImageType($source);
        switch($type)
        {
            case 'jpg':
                $type = 'jpeg';
            case 'jpeg':
            case 'png':
            case 'gif':
            case 'wbmp':
                return $func.$type;
                break;
            default:
                return false;
        }
    }

    /**
     * 获取图片类型
     * @param $source
     * @return bool|string
     */
    public function getImageType($source)
    {
        $imageInfo = getimagesize($source);
        if(!$imageInfo){
            return false;
        }
        $type = image_type_to_extension($imageInfo[2], false);
        if($type)
        {
            return $type;
        }
        else
        {
            return false;
        }
    }
}